package com.example.springcloudgateway.encrypt;

import com.example.springcloudgateway.util.CharsetUtil;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;

/**
 * @author yijie
 */
public class Md5 {

    final private static Logger logger = LoggerFactory.getLogger(Md5.class);

    /**
     * md5 string encrypt (utf-8)
     *
     * @param data    original string
     * @return md5 string
     */
    public static String encrypt(String data) {
        return encrypt(data, null);
    }

    /**
     * md5 string encrypt
     *
     * @param data    original string
     * @param charset charset (can be null)
     * @return md5 string
     */
    public static String encrypt(String data, String charset) {
        if (StringUtils.isEmpty(data)) {
            return "";
        }
        String c = CharsetUtil.getCharset(charset);
        String result = "";
        try {
            result = DigestUtils.md5Hex(data.getBytes(c));
        } catch (UnsupportedEncodingException e) {
            logger.error(e.getMessage());
        }
        return result;
    }

    /**
     * multi md5 string encrypt (utf-8)
     *
     * @param data    original string
     * @param time    encrypt times
     * @return md5 string
     */
    public static String repeatEncrypt(String data, int time) {
        return repeatEncrypt(data, time, null);
    }

    /**
     * multi md5 string encrypt
     *
     * @param data    original string
     * @param time    encrypt times
     * @param charset charset (can be null)
     * @return md5 string
     */
    public static String repeatEncrypt(String data, int time, String charset) {
        if (StringUtils.isEmpty(data)) {
            return "";
        }

        String result = encrypt(data, charset);
        for (int i = 1; i < time - 1; i++) {
            result = encrypt(result, charset);
        }
        return encrypt(result, charset);
    }

    /**
     * Md5 string encrypt with salt(key) (utf-8)
     *
     * @param data    original string
     * @param salt    key
     * @return md5 string
     */
    public static String encryptSalt(String data, String salt) {
        return encryptSalt(data, salt, null);
    }

    /**
     * Md5 string encrypt with salt(key)
     *
     * @param data    original string
     * @param salt    key
     * @param charset charset (can be null)
     * @return md5 string
     */
    public static String encryptSalt(String data, String salt, String charset) {
        return encrypt(new String(new StringBuilder().append(data).append(salt)), charset);
    }

    /**
     * md5 file encrypt
     *
     * @param file original file
     * @return md5 string
     */
    public static String encryptFile(File file) {
        String result = "";
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            MappedByteBuffer byteBuffer = fis.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
            MessageDigest md5 = MessageDigest.getInstance("Md5");
            md5.update(byteBuffer);
            byte[] resultBytes = md5.digest();

            StringBuilder sb = new StringBuilder();
            for (byte b : resultBytes) {
                if (Integer.toHexString(0xFF & b).length() == 1) {
                    sb.append("0").append(Integer.toHexString(0xFF & b));
                } else {
                    sb.append(Integer.toHexString(0xFF & b));
                }
            }
            result = new String(sb);
        } catch (Exception e) {
            logger.error(e.getMessage());
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    logger.error(e.getMessage());
                }
            }
        }
        return result;
    }

}
